package base.thread_demo.demo11;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 线程通信案例：子线程循环5次，接着主线程循环10次，
 *              接着又回到子线程循环5次，接着再回到主线程又循环10次，如此循环200次
 *
 */
public class CommunicationDemo2 {
    private static final Logger log = LoggerFactory.getLogger(CommunicationDemo2.class);

    public static void main(String[] args) {
        Business business = new Business();

        new Thread(()->{
            for (int i = 1; i <= 200; i++) {
                //log.info("{}--->{}",Thread.currentThread().getName(),i);
                try {
                    business.sub(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t1").start();

        for (int i = 1; i <= 200; i++) {
            try {
                business.main(i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 将子线程和主线程任务封装成一个Business对象
 * 主线程和子线程业务分别提取成独立方法，加同步逻辑时，持有的锁对象就是this
 */
class Business {
    private static final Logger log = LoggerFactory.getLogger(Business.class);
    // 主子线程轮换执行标志
    private boolean isSubExcute = true;

    public synchronized void sub(int j) throws InterruptedException {
        // while防止虚假唤醒
        // sub线程必循环200次,用if...else简单判断,导致被唤醒后,紧接着执行200次循环的下一次循环,丢失导致休眠的那一次循环.
        // 所以为了保证子线程200次都执行循环5次操作任务,那么必须循环遍历条件是否满足子线程执行的这个条件,即 isSubExcute
        // 是否代表当前该子线程运行,条件允许了,才放行,否则继续等待,被唤醒来后还要检测下 isSubExcute 条件是否满足
        while(!isSubExcute){
            this.wait();
        }
        for (int i = 1; i <= 5; i++) {
            log.info("sub thread sequence of {}, loop of {} ", i, j);
        }
        this.isSubExcute = !this.isSubExcute;
        this.notify();// 通知主线程可以执行了,但并不是主线程立马就执行要等子线程synchronized同步代码块执行完毕
    }

    public synchronized void main(int j) throws InterruptedException {
        while (this.isSubExcute){
            this.wait();// 轮到子线程执行，我释放锁对象
        }
        for (int i = 1; i <= 10; i++) {
            log.info("main thread sequence of {}, loop of {}", i, j);
        }
        this.isSubExcute = !this.isSubExcute;
        this.notify();
    }

}
